package com.example.yingjiguanli_demo.aspect;


import com.example.yingjiguanli_demo.utils.UserUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.JoinPoint;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
@Slf4j
public class RateLimiterAspect {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private UserUtils userUtils;

    private static final int MAX_REQUESTS = 5;  // 最大请求次数
    private static final long TIME_WINDOW = 60000;  // 时间窗口，单位：毫秒（例如 1 分钟）
    private static final String RATE_LIMIT_KEY_PREFIX = "rate_limit:";

    @Pointcut("@annotation(com.example.yingjiguanli_demo.aspect.interfaces.RateLimiter)")
    public void rateLimiterPointcut() {}

    @Before("rateLimiterPointcut()")
    public void before(JoinPoint joinPoint) throws Throwable {
        String key = generateKey(joinPoint);
        String redisKey = RATE_LIMIT_KEY_PREFIX + key;

        long currentTime = System.currentTimeMillis();
        String currentCount = stringRedisTemplate.opsForValue().get(redisKey);

        if (currentCount == null) {
            // 如果没有请求记录，设置初始请求次数为 1，并设置过期时间
            stringRedisTemplate.opsForValue().set(redisKey, "1", TIME_WINDOW, TimeUnit.MILLISECONDS);
        } else {
            int count = Integer.parseInt(currentCount);
            if (count >= MAX_REQUESTS) {
                throw new RuntimeException("请求过于频繁，请稍后再试！");
            }
            // 增加请求次数
            stringRedisTemplate.opsForValue().increment(redisKey, 1);
        }
    }

    /**
     * 生成 Redis Key
     *
     * @param joinPoint 切点信息
     * @return 生成的 Redis Key
     */
    private String generateKey(JoinPoint joinPoint) {
        HttpServletRequest request = getRequest();
        String sessionId = getSessionIdFromCookies(request);
        int userId = getUserUtils().getUserId(sessionId);
        log.info("获取到 userId: {}", userId);
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getName();
        log.info("返回redisKey");
        return userId + ":" + className + "." + methodName;
    }

    /**
     * 获取当前请求对象
     *
     * @return HttpServletRequest 对象
     */
    private HttpServletRequest getRequest() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        return attributes.getRequest();
    }

    /**
     * 从请求对象的 cookies 中获取 sessionId
     *
     * @param request HttpServletRequest 对象
     * @return sessionId
     */
    private String getSessionIdFromCookies(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        String sessionId = null;
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("SESSIONID".equals(cookie.getName())) {
                    log.info("获取到 SESSIONID: {}", cookie.getValue());
                    sessionId = cookie.getValue();
                }
            }
        }
        return sessionId;
    }

    /**
     * 获取 UserUtils 工具类实例
     *
     * @return UserUtils 实例
     */
    private UserUtils getUserUtils() {
        return userUtils;
    }

}


